package com.imooc.coupon.executor;

import com.alibaba.fastjson.JSON;
import com.imooc.coupon.support.vo.GoodsInfo;
import com.imooc.coupon.support.vo.SettlementInfo;
import org.apache.commons.collections4.CollectionUtils;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 优惠券结算规则执行器抽象实现（通用工具方法定义）
 *
 * Created By TINY
 * Create Time 2020/2/12
 **/
public abstract class AbstractExecutor implements RuleExecutor {

    /**
     * 实现单品类优惠券的规则校验（校验优惠券是否支持商品类型），商品只要符合
     * 一个优惠券支持的商品类型即可；组合类优惠券需要重载此方法完成对应实现
     *
     * @param settlementInfo {@link SettlementInfo} 结算信息对象
     * @return 是否支持商品类型
     */
    protected boolean isGoodsTypeSupported(SettlementInfo settlementInfo) {

        // 结算对象中的商品类型
        List<Integer> goodsTypes = settlementInfo.getGoodsInfos()
                .stream().map(GoodsInfo::getType)
                .collect(Collectors.toList());

        // 优惠券支持的商品类型
        @SuppressWarnings("all")
        List<Integer> goodsTypeFromTemplate = JSON.parseObject(
                settlementInfo.getCouponAndTemplateInfos().get(0)
                        .getTemplate().getRule()
                        .getUsageScope().getGoodsType(), List.class
        );

        // 两者商品类型存在交集即满足条件
        return (CollectionUtils.isNotEmpty(
                CollectionUtils.intersection(goodsTypes, goodsTypeFromTemplate)
        ));
    }

    /**
     * 当优惠券不支持对应商品类型的结算时，修改 {@link SettlementInfo} 中的信息
     *
     * @param settlementInfo {@link SettlementInfo} 结算信息对象
     * @param sumPrice 商品原始总价
     * @return {@link SettlementInfo} 修改后的结算信息对象
     */
    protected SettlementInfo processGoodsTypeNotSupport(
            SettlementInfo settlementInfo, Double sumPrice
    ) {

        // 判断优惠券是否支持商品结算
        boolean goodsTypeSupported = isGoodsTypeSupported(settlementInfo);

        if (!goodsTypeSupported) { // 不支持！
            settlementInfo.setCost(sumPrice); // 设置金额为原始总价

            settlementInfo.setCouponAndTemplateInfos(
                    Collections.emptyList()); // 因为优惠券不支持结算，清空

            return settlementInfo;
        }
        return null; // 优惠券支持商品结算
    }

    /**
     * 计算所有商品的总价
     *
     * @param goodsInfos {@link GoodsInfo} 商品信息
     * @return 商品总价
     */
    protected double computeAllGoodsCost(List<GoodsInfo> goodsInfos) {
        return goodsInfos.stream()
                .mapToDouble(g -> g.getPrice() * g.getCount()).sum();
    }

    /**
     * 将数值保留两位小数并返回（使用四舍五入进位策略）
     * @param value 浮点数值
     * @return 四舍五入后的保留两位小数的浮点数
     */
    @SuppressWarnings("all")
    protected double retain2Decimals(double value) {
        return new BigDecimal(value).setScale(
                2, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
     * 用户最小的支付费用，不能是负数
     *
     * @return 用户最小支付费用
     */
    protected double minCost() {  return 0.1; }
}
